package com.niuwa.p2p.core.utils;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


public class DateUtil {
	public static final String PARAM_DISPLAY_DATEFORMAT = "dd-MMM-yyyy";

	public static final int NO_CHANGE = -1;

	public static final int MILLIS_OF_DAY = 24 * 60 * 60 * 1000;
	
	public static final String DATE_FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";
	
	public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";

	/**
	 * Get an instance with given zone and date. *
	 * 
	 * @param zoneID
	 * @param date
	 * @return Calendar
	 */
	public static Calendar getCalendar(String zoneID, Date date) {
		TimeZone tz = TimeZone.getTimeZone(zoneID);
		Calendar c = Calendar.getInstance(tz);
		c.setTime(date);
		return c;
	}

	/**
	 * 
	 * Truncate the specified (signed) fields, based on the given time format
	 * and the calendar's rules.
	 * 
	 * @param zoneID
	 * @param date
	 * @param field
	 * @param amount
	 * @param format
	 *            : Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calend
	 *            ar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND,
	 *            Calendar.MILLISECOND
	 * @return Calendar
	 */
	public static Calendar truncTimeByZone(String zoneID, Date date, int field,
			int amount, int format) {
		/* Get an instance with given zone and date. */
		Calendar c = getCalendar(zoneID, date);

		/*
		 * Adds the specified (signed) amount of time to the given time field,
		 * based on the calendar's rules.
		 */
		c.add(field, amount);

		/*
		 * Trucate the specified (signed) fields, based on the given time form
		 * at and the calendar's rules.
		 */
		switch (format) {
		case Calendar.YEAR:
			c.set(Calendar.MONTH, 0);
		case Calendar.MONTH:
			c.set(Calendar.DAY_OF_MONTH, 0);
		case Calendar.DAY_OF_MONTH:
			c.set(Calendar.HOUR_OF_DAY, 0);
		case Calendar.HOUR_OF_DAY:
			c.set(Calendar.MINUTE, 0);
		case Calendar.MINUTE:
			c.set(Calendar.SECOND, 0);
		case Calendar.SECOND:
			c.set(Calendar.MILLISECOND, 0);
		case Calendar.MILLISECOND:
			break;
		default:
			throw new IllegalArgumentException();
		}
		return c;
	}

	/**
	 * Usage return ceiling days between the date1 and date2 at the designated
	 * time zone.
	 * 
	 * @param zoneID
	 * @param date1
	 * @param date2
	 * @return int
	 */
	public static int ceilIntervalDay(String zoneID, Date date1, Date date2) {

		Calendar c1 = truncTimeByZone(zoneID, date1, Calendar.MILLISECOND, 0,
				Calendar.DAY_OF_MONTH);
		Calendar c2 = truncTimeByZone(zoneID, date2, Calendar.MILLISECOND, 0,
				Calendar.DAY_OF_MONTH);
		int interval = (int) Math.round(((double) (c2.getTimeInMillis() - c1
				.getTimeInMillis())) / 86400000.0) + 1;
		return interval;
	}

	public static Date getFormattedDate(String pattern, String val) {
		if ("".equals(val) || val == null) {
			return null;
		}
		SimpleDateFormat formatter = new SimpleDateFormat(pattern);
		ParsePosition pos = new ParsePosition(0);
		return formatter.parse(val, pos);
	}

	// Usage DateHelper.showFormatedDate ( PARAM_DISPLAY_DATEFORMAT , new Date

	// () ) );
	public static String showFormatedDate(String pattern, Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat(pattern);
		String dateString = formatter.format(date);
		return dateString;
	}

	static DateFormat format1 = new java.text.SimpleDateFormat("MM月dd日 hh:mm");

	public static String showFormatedDate(String longDate) {
		return format1.format(new Date(new Long(longDate)));
	}

	// Usage return day different in double for date1 and date2
	public static double diffDates(Date date1, Date date2) {
		long t1 = date1.getTime();
		long t2 = date2.getTime();
		return (double) (t2 - t1) / 86400000;
	}

	public static Date roundToHour(Date date) {
		// msec in hour
		long dateLong = (long) (date.getTime() / 3600000L);
		return new Date(dateLong * 3600000L);
	}

	public static Date roundToLaterHour(Date date) {
		// msec in hour
		long dateLong = date.getTime();
		if (dateLong % 3600000L == 0) {
			return new Date(dateLong);
		} else {
			return new Date((dateLong / 3600000L + 1) * 3600000L);
		}
	}

	public static Date addSeconds(Date date, int second) {
		long dateTime = date.getTime() + (long) second * 1000L;
		return new Date(dateTime);
	}

	public static Date addMinutes(Date date, int minute) {
		long dateTime = date.getTime() + (long) minute * 60000L;
		return new Date(dateTime);
	}

	public static Date addHours(Date date, int hour) {
		// msec in hour
		long dateLong = date.getTime() + (long) hour * 3600000L;
		return new Date(dateLong);
	}

	public static Date addDays(Date date, int day) {
		return addHours(date, day * 24);
	}

	public static Date addMonths(Date date, int month) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.MONTH, month);
		return c.getTime();
	}

	public static Date addYears(Date date, int year) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.YEAR, year);
		return c.getTime();
	}
//TODO modify
	
//	public static Date addDays(Date date, String duration) {
//		if (DurationConstants.DURATION_DAY.equals(duration)) {
//			return addDays(date, 1);
//		} else if (DurationConstants.DURATION_WEEK.equals(duration)) {
//			return addDays(date, 7);
//		} else if (DurationConstants.DURATION_TWO_WEEK.equals(duration)) {
//			return addDays(date, 14);
//		} else if (DurationConstants.DURATION_MONTH.equals(duration)) {
//			return addMonths(date, 1);
//		} else if (DurationConstants.DURATION_SEASON.equals(duration)) {
//			return addMonths(date, 3);
//		} else if (DurationConstants.DURATION_HALF_YEAR.equals(duration)) {
//			return addMonths(date, 6);
//		} else if (DurationConstants.DURATION_YEAR.equals(duration)) {
//			return addYears(date, 1);
//		}
//		return null;
//	}
//
//	public static Date precedingDays(Date date, String duration) {
//		if (DurationConstants.DURATION_DAY.equals(duration)) {
//			return addDays(date, -1);
//		} else if (DurationConstants.DURATION_WEEK.equals(duration)) {
//			return addDays(date, -7);
//		} else if (DurationConstants.DURATION_TWO_WEEK.equals(duration)) {
//			return addDays(date, -14);
//		} else if (DurationConstants.DURATION_MONTH.equals(duration)) {
//			return addMonths(date, -1);
//		} else if (DurationConstants.DURATION_SEASON.equals(duration)) {
//			return addMonths(date, -3);
//		} else if (DurationConstants.DURATION_HALF_YEAR.equals(duration)) {
//			return addMonths(date, -6);
//		} else if (DurationConstants.DURATION_YEAR.equals(duration)) {
//			return addYears(date, -1);
//		}
//		return null;
//	}

	public static Date getDateInGMT() {
		return new Date(createDateToMinute().getTime()
				- java.util.TimeZone.getDefault().getRawOffset());
	}

	public static Date getDateAccurateInGMT() {
		return new Date(createDateToSecond().getTime()
				- java.util.TimeZone.getDefault().getRawOffset());
	}

	public static Date getDateInGMT(Date date) {
		return new Date(date.getTime()
				- java.util.TimeZone.getDefault().getRawOffset());
	}

	public static Date trimSeconds(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date trimSecondsToEnd(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
	}

	public static Date createDateToMilliSecond() {
		Calendar cal = Calendar.getInstance();
		return cal.getTime();
	}

	public static Date createDateToSecond() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date createDateToMinute() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date createDate() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date createDate(int year, int month, int day) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		cal.set(Calendar.DAY_OF_MONTH, day);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date createDate(int year, int month, int day, int hour,
			int minute) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		cal.set(Calendar.DAY_OF_MONTH, day);
		cal.set(Calendar.HOUR_OF_DAY, hour);
		cal.set(Calendar.MINUTE, minute);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	public static Date getDateInLocal(Date gmtDate) {
		return new Date(gmtDate.getTime()
				+ java.util.TimeZone.getDefault().getRawOffset());
	}

	public static String getSQLDateString(Date date) {
		return "to_date('" + showFormatedDate("MM/dd/yyyy HH:mm:ss", date)
				+ "','MM/DD/YYYY HH24:MI:SS')";
	}

	public static String getSQLDateStringWithoutTime(Date date) {
		return "to_date('" + showFormatedDate("MM/dd/yyyy", date)
				+ "','MM/DD/YYYY')";
	}

	public static int getYear(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.YEAR);
	}

	public static int getMonth(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.MONTH);
	}

	public static int getDay(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.DAY_OF_WEEK);
	}

	public static int getDate(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.DAY_OF_MONTH);
	}

	public static int getHour(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.HOUR_OF_DAY);
	}

	public static int getMinute(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.MINUTE);
	}

	public static int getSecond(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		return c.get(Calendar.SECOND);
	}

	public static void setYear(Date aDate, int year) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.YEAR, year);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setMonth(Date aDate, int month) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.MONTH, month);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setDay(Date aDate, int dayOfMonth) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.DAY_OF_WEEK, dayOfMonth);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setDate(Date aDate, int dayOfMonth) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setHour(Date aDate, int hour24) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.HOUR_OF_DAY, hour24);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setMinute(Date aDate, int minute) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.MINUTE, minute);
		aDate.setTime(c.getTime().getTime());
	}

	public static void setSecond(Date aDate, int second) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.SECOND, second);
		aDate.setTime(c.getTime().getTime());
	}

	// return a Date with only the year, month & day retained (i.e. the time

	// part is truncated)
	public static Date trimTime(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTime();
	}

	// return Date with 23:59:59:999
	public static Date trimTimeToEnd(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.set(Calendar.HOUR_OF_DAY, 23);
		c.set(Calendar.MINUTE, 59);
		c.set(Calendar.SECOND, 59);
		c.set(Calendar.MILLISECOND, 999);
		return c.getTime();
	}

	// Based on time zone, return a Date with only the year, month & day
	// retained (i.e. the time part is truncated)
	public static Date trimTimeByZone(Date aDate) {
		return aDate;
	}

	// Based on time zone, return Date with 23:59:59:999
	public static Date trimTimeToEndByZone(Date aDate) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		c.add(Calendar.DATE, 1);
		c.add(Calendar.SECOND, -1);
		return c.getTime();
	}

	public static Date alterDate(Date aDate, int year, int month, int date,
			int hour, int minute, int second, int milliSecond) {
		Calendar c = Calendar.getInstance();
		c.setTime(aDate);
		if (year != NO_CHANGE) {
			c.set(Calendar.YEAR, year);
		}
		if (month != NO_CHANGE) {
			c.set(Calendar.MONTH, month);
		}
		if (date != NO_CHANGE) {
			c.set(Calendar.DAY_OF_MONTH, date);
		}
		if (hour != NO_CHANGE) {
			c.set(Calendar.HOUR_OF_DAY, hour);
		}
		if (minute != NO_CHANGE) {
			c.set(Calendar.MINUTE, minute);
		}
		if (second != NO_CHANGE) {
			c.set(Calendar.SECOND, second);
		}
		if (milliSecond != NO_CHANGE) {
			c.set(Calendar.MILLISECOND, milliSecond);
		}
		return c.getTime();
	}

	public static String formatDateToString(Date date) {
		return formatDateToString(date, PARAM_DISPLAY_DATEFORMAT);
	}

	
	public static String formatDateToString(Date date, String format) {
		return formatDateToString(null, date, format);
	}

	//TODO  modify
//	public static String formatDateRangeToString(Date dateFrom, Date dateTo,
//			String format) throws Exception {
//		if (isSameDay(dateFrom, dateTo)) {
//			return formatDateToString(dateFrom, format) + " "
//					+ PropertiesUtil.getProperty("to") + " "
//					+ formatDateToString(dateTo, "HH:mm");
//		} else {
//			return formatDateToString(dateFrom, format) + " "
//					+ PropertiesUtil.getProperty("to") + " "
//					+ formatDateToString(dateTo, format);
//		}
//	}

	public static Boolean isSameDay(Date date1, Date date2) {
		if (getYear(date1) == getYear(date2)
				&& getMonth(date1) == getMonth(date2)
				&& getDate(date1) == getDate(date2)) {
			return true;
		} else {
			return false;
		}
	}

	public static Boolean isSameDate(Date date1, Date date2) {
		if (date1.getTime() == date2.getTime()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Format the date based on the time zone and the format.
	 * 
	 * @param zoneId
	 * @param date
	 * @param format
	 * @return String
	 */
	public static String formatDateToString(String zoneId, Date date,
			String format) {
		String result = null;
		if (date == null) {
			result = "";
		} else {
			SimpleDateFormat stdFormat = new SimpleDateFormat(format);
			if (zoneId != null && !"".equals(zoneId)) {
				stdFormat.setTimeZone(TimeZone.getTimeZone(zoneId));
			}
			result = stdFormat.format(date);
		}
		return result;
	}

	public static Date convertDateforClient(Date date) {
		Date result = date;
		if (result != null) {
			if (getYear(result) <= 2) {
				result = null;
			}
		}
		return result;
	}

	public static Date getFirstDateInMonth(Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		String logEntry = formatter.format(date);
		Date today = null;
		try {
			today = formatter.parse(logEntry);
		} catch (Exception exc) {
			exc.printStackTrace();
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(today);
		cal.set(Calendar.DAY_OF_MONTH, 1);

		return cal.getTime();
	}
	
	public static Boolean isRecent(Date dateTime, int days) {
		if(dateTime == null){
			return false;
		}
		if((new Date()).getTime() - dateTime.getTime()<86400000*days){
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * 字符串格式化Date类型
	 * 
	 * @param dateStr
	 * @param format
	 * @return
	 * @throws Exception
	 */
	public static Date parseStringToDate(String dateStr, String format) throws Exception {
		try {
			SimpleDateFormat sdf = getSimpleDateFormat(format);
			return sdf.parse(dateStr);
		} catch (Exception ex) {
			return null;
		}
	}
	public static SimpleDateFormat getSimpleDateFormat(String format)throws Exception {
		try {
			return new SimpleDateFormat(format);
		} catch (Exception ex) {
			return new SimpleDateFormat(DATE_FORMAT_LONG);
		}
	}
	/**
	 * yyyy-MM-dd格式的字符串格式化为yyyy年MM月DD日格式
	 * 
	 * @param strYmd
	 * @return
	 */
	public static String changeYmd(String strYmd) {
		if (strYmd == null || strYmd.length() != 10)
			return " ";
		else
			return strYmd.substring(0, 4) + "年" + strYmd.substring(5, 7) + "月" + strYmd.substring(8, 10) + "日";
	}

	 //判断<firstDate>时间点是否在<secondDate>时间点之前
    public static boolean isBefore(Date firstDate, Date secondDate) {

        return compare(firstDate, secondDate) < 0 ? true : false;
    }
    
    //判断<secondDate>时间点是否在<firstDate>时间点之后
    public static boolean isAfter(Date secondDate, Date firstDate) {

        return compare(secondDate, firstDate) > 0 ? true : false;
    }

    public static int compare(Date firstDate, Date secondDate) {
        Calendar firstCalendar = null;
        if (firstDate != null) {
            firstCalendar = Calendar.getInstance();
            firstCalendar.setTime(firstDate);
        }
        Calendar secondCalendar = null;
        if (secondDate != null) {
            secondCalendar = Calendar.getInstance();
            secondCalendar.setTime(secondDate);
        }
        try {
            return firstCalendar.compareTo(secondCalendar);
        } catch (NullPointerException e) {
            throw new IllegalArgumentException(e);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(e);
        }
    } 
    
    
    /** 
     * 取得当月天数 
     * */  
    public static int getCurrentMonthLastDay()  
    {  
        Calendar a = Calendar.getInstance();  
        a.set(Calendar.DATE, 1);//把日期设置为当月第一天  
        a.roll(Calendar.DATE, -1);//日期回滚一天，也就是最后一天  
        int maxDate = a.get(Calendar.DATE);  
        return maxDate;  
    }  
      
    /** 
     * 得到指定月的天数 
     * */  
    public static int getMonthLastDay(int year, int month)  
    {  
        Calendar a = Calendar.getInstance();  
        a.set(Calendar.YEAR, year);  
        a.set(Calendar.MONTH, month - 1);  
        a.set(Calendar.DATE, 1);//把日期设置为当月第一天  
        a.roll(Calendar.DATE, -1);//日期回滚一天，也就是最后一天  
        int maxDate = a.get(Calendar.DATE);  
        return maxDate;  
    }
    
    /**
     * 计算两个日期之间相差的天数
     * @param dataFrom 开始的时间
     * @param dataTo   结束的时间
     * @return 相差天数
     * @throws Exception
     */ 
    public static int getDaysBetween(Date dataFrom,Date dataTo) throws Exception { 
    	return getDaysBetween(formatDateToString(dataFrom, DATE_FORMAT_YYYY_MM_DD), formatDateToString(dataTo, DATE_FORMAT_YYYY_MM_DD));
    }

    /**
     * 字符串的日期格式的计算
     * @param dataFrom 开始的时间
     * @param dataTo   结束的时间
     * @return 相差天数
     * @throws Exception
     */ 
    public static int getDaysBetween(String dataFrom,String dataTo) throws Exception{
    	
        Calendar cal = Calendar.getInstance(); 
        cal.setTime(parseStringToDate(dataFrom, DATE_FORMAT_YYYY_MM_DD)); 
        long time1 = cal.getTimeInMillis ();              
        cal.setTime(parseStringToDate(dataTo, DATE_FORMAT_YYYY_MM_DD)); 
        long time2 = cal.getTimeInMillis ();      
        long between_days=(time2-time1)/ (1000*3600*24);
        return Integer.parseInt(String.valueOf (between_days));  
    }
    
    /**
     * d1 与 d2相隔天数
     * @param d1
     * @param d2
     * @return
     */
    public static long getSubDay(Date d1,Date d2){
    	return (d1.getTime() - d2.getTime())/(24*60*60*1000);
    }
    
    /**
	 * 获取n个月时间 format:"yyyy-MM-dd HH:mm:ss"
	 */
	public static Date getNextMonthTime(int month, String format) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, month);
		Date d = calendar.getTime();
		return d;
	}
	/**
	 * 获取传入时间的前n天或后n天
	 * format:"yyyy-MM-dd HH:mm:ss"
	 */
	public static Date getNextDayTime(int day, String format, Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int d = calendar.get(Calendar.DATE);
		calendar.set(Calendar.DATE,d+day);
		return calendar.getTime();
	}
}
